/*--------------------------------------------------------------------------------
* Copyright (c) 2023,西北农林科技大学信息学院计算机科学系ArcaneGuo
* All rights reserved.
*
* 文件名称：main.c
* 文件标识：见配置管理计划书
* 摘要：载入当前路径下的地图文件，进行走迷宫游戏。
*
* 说明：重构了代码逻辑，使得代码更加易于拓展和维护，总体功能不变，细节略有拓展
*
* 当前版本：2.0
* 作者：ArcaneGuo
* 完成日期：2023年12月29日
*
* 取代版本：1.2
* 作者：ArcaneGuo
* 完成日期：2023年12月28日
--------------------------------------------------------------------------------*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct
{
	int x;
	int y;
}MapData;  //文件中的元素有几行几列

typedef struct
{
    char user_name[20];
    int user_level;
}UserData;  //用户系统中的用户数据

typedef struct
{
    char username[20];
    char userrole;
    int x;
    int y;
}player;  //游戏进行时的用户数据



//这个版本的用到文件的函数都是在函数中打开在函数中关闭
//这个版本的自定义函数中没有调用其他自定义函数（除了封装器函数）



//封装器函数
int PlayingOneMap(UserData);  //游戏结束返回0，否则返回1

//自定义函数
void PrintEnterGameGuide(void);  //仅用于打印出开局提示文字
void ReadPlayerName(char *);  //把玩家输入的字符写入传入的数组中
int FindUserLevel(char *);  //传入用户名，在data.txt中寻找，如果找到了返回玩家所在关卡，如果没找到返回-1
int InitUser(char *);  //传入需要新建的用户名，改写文件中的内容，同样返回关卡（0）

MapData count_file(FILE *);  //统计地图中的元素，控制循环

MapData LoadMap(int level, char *** pmap_dynamic);  //传入玩家的等级（0、1、2...)和动态二维数组的指针的地址，返回地图的数据
void OutputMap(char **, MapData);  //传入一个首地址然后打印出这个地图



int main()
{

    PrintEnterGameGuide();

    UserData user;
    ReadPlayerName(user.user_name);
    user.user_level = FindUserLevel(user.user_name);
    if(user.user_level == -1)
    {
        InitUser(user.user_name);
        user.user_level = 0;
    }

    while(PlayingOneMap(user)){};

    return 0;

}

//--------------------------------------------------------
// 名称: int PlayingOneMap(UserData user)
// 功能: 启动游戏的封装器函数
// 参数: 
//       [UserData user] ---- 登录游戏的用户
// 返回: [int] ------ 返回0代表游戏结束
// 作者: ArcaneGuo
// 日期: 2024年1月20日
//--------------------------------------------------------
int PlayingOneMap(UserData user)
{
    char ** pmap_dynamic = NULL;
    MapData current_map_data = LoadMap(user.user_level, &pmap_dynamic);

    player player1;
	player1.x = 0;
	player1.y = 0;
    
    scanf("%*[^\n]");
    scanf("%*c");
    printf("请输入你的角色:\n");
    printf("(一个符号，如“@”)\n");

    char role;
    scanf("%c", &role);
    player1.userrole = role;

    char player_input;
    while(player1.x != (current_map_data.x - 1) || player1.y != (current_map_data.y - 2))
    {
        pmap_dynamic[player1.x][player1.y] = player1.userrole;

        OutputMap(pmap_dynamic, current_map_data);
        
        scanf("%c", &player_input);

        switch(player_input)
        {
            case 'w': case 'W':          
                player1.x -= 1;
                pmap_dynamic[player1.x + 1][player1.y] = ' '; 
                break;
            case 'a': case 'A':
                player1.y -= 1;
                pmap_dynamic[player1.x][player1.y + 1] = ' '; 
                break;
            case 's': case 'S':
                player1.x += 1;
                pmap_dynamic[player1.x - 1][player1.y] = ' '; 
                break;
            case 'd': case 'D':
                player1.y += 1;
                pmap_dynamic[player1.x][player1.y - 1] = ' '; 
                break;
        }
        
        if(player1.x < 0 || player1.y < 0 || player1.x > current_map_data.x || player1.y > current_map_data.y || pmap_dynamic[player1.x][player1.y] == '#')
        {
            switch(player_input)
            {
                case 'w': 
                    player1.x += 1;
                    break;
                case 'a': 
                    player1.y += 1;
                    break;
                case 's': 
                    player1.x -= 1;
                    break;
                case 'd': 
                    player1.y -= 1;
                    break;
            }
        }

        pmap_dynamic[player1.x][player1.y] = player1.userrole;
        
    }

    OutputMap(pmap_dynamic, current_map_data);
	printf("Win!\n");

    return 0;
}

//--------------------------------------------------------
// 名称: MapData count_file(FILE * fpmap)
// 功能: 统计地图文件中地图的长宽
// 参数: 
//       [FILE * fpmap] ---- 地图文件指针
// 返回: [MapData] ------ 地图文件的长宽
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
MapData count_file(FILE * fpmap)
{
    int x = 1, y = 1;
    int ch;
    while((ch = fgetc(fpmap)) != '\n')
    {
        y++;
    } 
    rewind(fpmap);

    while((ch = fgetc(fpmap)) != EOF)
    {
        if((ch == '\n'))
        {
            x++;
        }
    }
    rewind(fpmap);

    MapData current_map_data;
    current_map_data.x = x;
    current_map_data.y = y;

    rewind(fpmap);

    return current_map_data;
}

//--------------------------------------------------------
// 名称: MapData LoadMap(int level, char *** pmap_dynamic)
// 功能: 载入地图
// 参数: 
//       [int level] ---- 地图的等级
//       [char *** pmap_dynamic] ---- 储存临时保存地图的动态二维数组的首地址的指针的地址
// 返回: [MapData] ------ 载入的地图的长宽数据，用于控制循环
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
MapData LoadMap(int level, char *** pmap_dynamic)
{
    char map_lookup_table [20][20] = {"level0.txt", "level1.txt", "level2.txt"};
    
    FILE * fpmap = NULL;
    fpmap = fopen(map_lookup_table[level], "r+");
    if(fpmap == NULL)
    {
        printf("Error: Fail to open <mapname>.txt\n");
        exit(1);
    }

    MapData current_map = count_file(fpmap);

    (*pmap_dynamic) = (char **)malloc(current_map.x * sizeof(char *));
    if((*pmap_dynamic) == NULL)
    {
        printf("Not enough memory!\n");
		exit(1);
    }

    for(int i = 0; i < current_map.x; i++)
    {
        (*pmap_dynamic)[i] = (char *)malloc(current_map.y * sizeof(char));
        if((*pmap_dynamic)[i] == NULL)
        {
            printf("Not enough memory!\n");
			free(*pmap_dynamic);
            exit(1);
        }
    }

    int i, j, ch;
    for(i = 0; i < current_map.x; i++)
    {
        for(j = 0; j < current_map.y; j++)
        {
            ch = fgetc(fpmap);
            (*pmap_dynamic)[i][j] = ch;
        }
    }

    fclose(fpmap);

    return current_map;
}

//--------------------------------------------------------
// 名称: int InitUser(char * pname)
// 功能: 在data.txt文件中写入新玩家的数据
// 参数: 
//       [char * pname] ---- 保存玩家名称数组的首地址
// 返回: [int] ------ 玩家的地图的等级
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
int InitUser(char * pname)
{
    FILE * fpdata = NULL;
    fpdata = fopen ("data.txt", "r+");
    if(fpdata == NULL)
    {
        printf("Error: Failed to open data.txt\n");
        exit(1);
    }

    fseek(fpdata, 0, SEEK_END);
    fprintf(fpdata, "\n%s", pname);
    fprintf(fpdata, " %d", 0);

    fclose(fpdata);
    return 0;
}

//--------------------------------------------------------
// 名称: int FindUserLevel(char * pname)
// 功能: 在data.txt中寻找用户输入的玩家名对应的地图等级
// 参数: 
//       [char * pname] ---- 保存玩家名称数组的首地址
// 返回: [int] ------ 玩家的地图的等级
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
int FindUserLevel(char * pname)
{
    FILE * fpdata = NULL;
    fpdata = fopen("data.txt", "r");
    if(fpdata == NULL)
    {
        printf("Error: Failed to open data.txt\n");
        exit(1);
    }

    char data_username[20] = {0};
    int level = 0;
    while(!feof(fpdata))
    {
        fscanf(fpdata, "%s %d", data_username, &level);
        fscanf(fpdata, "%*[^\n]");
        fscanf(fpdata, "%*c");

        if(strcmp(pname, data_username) == 0)
        {
            fclose(fpdata);
            return level;
        }
    }

    fclose(fpdata);
    return -1;
}

//--------------------------------------------------------
// 名称: void PrintEnterGameGuide(void)
// 功能: 打印出引导玩家进入游戏的语句
// 参数: 
//       [void] ---- 无
// 返回: [void] ------ 无
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
void PrintEnterGameGuide(void)
{
    printf("\n");
    printf("########################################################################################\n");

    printf("Welcome to the Labyrinth game!\n");
    printf("Please enter your username:\n");
    printf("(If you didn`t have one, we will automatically register for you)\n");

}

//--------------------------------------------------------
// 名称: void ReadPlayerName(char * pname)
// 功能: 读入玩家输入的用户名
// 参数: 
//       [char * pname] ---- 保存玩家名称数组的首地址
// 返回: [void] ------ 无
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
void ReadPlayerName(char * pname)
{
    scanf("%s", pname);
}

//--------------------------------------------------------
// 名称: void OutputMap(char ** pmap_dynamic, MapData current_map_data)
// 功能: 输出当前临时二维数组中储存的地图
// 参数: 
//       [char ** pmap_dynamic] ---- 动态二维数组的首地址
//       [MapData current_map_data] ---- 地图的长宽数据
// 返回: [void] ------ 无
// 作者: ArcaneGuo
// 日期: 2023年12月29日
//--------------------------------------------------------
void OutputMap(char ** pmap_dynamic, MapData current_map_data)
{
    for(int i = 0; i < current_map_data.x; i++)
    {
        for(int j = 0; j < current_map_data.y; j++)
        {
            printf("%c", pmap_dynamic[i][j]);
        }
    }
    printf("\n\n\n");
}
